package de.justphil.tcg.tcgserver.commons.management;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import de.justphil.tcg.tcgserver.commons.domain.Card;
import de.justphil.tcg.tcgserver.commons.domain.CardInstance;
import de.justphil.tcg.tcgserver.commons.domain.Deck;
import de.justphil.tcg.tcgserver.commons.domain.Game;
import de.justphil.tcg.tcgserver.commons.domain.Property;
import de.justphil.tcg.tcgserver.commons.domain.User;
import de.justphil.tcg.tcgserver.commons.domain.collections.CardInstanceCollection;
import de.justphil.tcg.tcgserver.commons.domain.complete.CCard;
import de.justphil.tcg.tcgserver.commons.domain.complete.CCardInstance;
import de.justphil.tcg.tcgserver.commons.domain.complete.CDeck;
import de.justphil.tcg.tcgserver.commons.domain.complete.CGame;
import de.justphil.tcg.tcgserver.commons.domain.complete.CNewGame;
import de.justphil.tcg.tcgserver.commons.domain.complete.CProperty;
import de.justphil.tcg.tcgserver.commons.domain.complete.CUser;
import de.justphil.tcg.tcgserver.commons.domain.containers.NewGame;
import de.justphil.tcg.tcgserver.commons.exceptions.TCGException;

public class ClusterBrowser {
	
	private final DataManager dataManager;
	
	
	public ClusterBrowser(DataManager dataManager) {
		this.dataManager = dataManager;
	}
	
	
	/* ######################################################################## */
	/* ######################################################################## */
	/* ######################################################################## */
	
	
	public Collection<CUser> getAllUsers() {
		
		Collection<User> users = dataManager.getAllUsers();
		
		return transformUsersCollection(users);
	}
	
	public Collection<CGame> getAllGames() {
		
		Collection<Game> games = dataManager.getAllGames();
		
		return transformGamesCollection(games);
	}
	
	public Collection<CNewGame> getAllNewGames() {
		
		Collection<NewGame> newGames = dataManager.getAllNewGames();
		
		return transformNewGamesCollection(newGames);
	}
	
	public Collection<CDeck> getAllDecks() throws TCGException {
		
		Collection<Deck> decks = dataManager.getAllDecks();
		
		return transformDecksCollection(decks);
	}
	
	public Collection<CCard> getAllCards() {
		
		Collection<Card> cards = dataManager.getAllCards();
		
		return transformCardsCollection(cards);
	}
	
	public Collection<CProperty> getAllProperties() {
		
		Collection<Property> properties = dataManager.getAllProperties();
		
		return transformPropertiesCollection(properties);
	}
	
	public Collection<CCardInstance> getAllCardInstances() throws TCGException {
		
		Collection<CardInstance> cis = dataManager.getAllCardInstances();
		
		return transformCardInstancesCollection(cis);
	}
	
	public Collection<CGame> getUserGames(long userId) throws TCGException {
		
		Collection<Game> userGames = dataManager.getUserGames(userId);
		
		return transformGamesCollection( userGames );
	}
	
	public Collection<CCardInstance> getUserCardInstances(long userId) throws TCGException {
		
		Collection<CardInstance> userCis = dataManager.getUserCardInstances(userId);
		return transformCardInstancesCollection(userCis);
	}
	
	public Collection<CCardInstance> getDeckCardInstances(long deckId) throws TCGException {
		
		Collection<CardInstance> deckCIs = dataManager.getDeckCardInstances(deckId);
		return transformCardInstancesCollection(deckCIs);
	}
	
	public Collection<CDeck> getUserDecks(long userId) throws TCGException {
		
		Collection<Deck> userDecks = dataManager.getUserDecks(userId);
		return transformDecksCollection(userDecks);
	}
	
	public Collection<CCardInstance> getCardCardInstances(long cardId) throws TCGException {
		
		Collection<CardInstance> cardCIs = dataManager.getCardCardInstances(cardId);
		return transformCardInstancesCollection(cardCIs);
	}
	
	
	/* ######################################################################## */
	/* ######################################################################## */
	/* ######################################################################## */
	
	private Collection<CCardInstance> transformCardInstancesCollection(Collection<CardInstance> cis) throws TCGException {
		Collection<CCardInstance> transformedCis = new ArrayList<CCardInstance>(cis.size());
		
		for (CardInstance ci : cis) {
			transformedCis.add( transformCardInstance( ci ) );
		}
		
		return transformedCis;
	}
	
	private Collection<CDeck> transformDecksCollection(Collection<Deck> decks) {
		Collection<CDeck> transformedDecks = new ArrayList<CDeck>(decks.size());
		
		for (Deck deck : decks) {
			transformedDecks.add( transformDeck( deck ) );
		}
		
		return transformedDecks;
	}
	
	private Collection<CGame> transformGamesCollection(Collection<Game> games) {
		Collection<CGame> completeUserGames = new ArrayList<CGame>( games.size() );
		
		
		for (Game g : games) {
			completeUserGames.add( new CGame( g.getId(), g.getWinnerId(),
					g.getPlayers(), g.getState(), g.getCreated(), g.getModified() ));
		}
		
		return completeUserGames;
	}
	
	private Collection<CNewGame> transformNewGamesCollection(Collection<NewGame> newGames) {
		Collection<CNewGame> completeNewGames = new ArrayList<CNewGame>( newGames.size() );
		
		
		for (NewGame ng : newGames) {
			completeNewGames.add( transformNewGame(ng) );
		}
		
		return completeNewGames;
	}
	
	private Collection<CUser> transformUsersCollection( Collection<User> users) {
		Collection<CUser> transformedUsers = new ArrayList<CUser>( users.size() );
		
		for (User u : users) {
			transformedUsers.add( transformUser(u) );
		}
		
		return transformedUsers;
	}
	
	private Collection<CCard> transformCardsCollection( Collection<Card> cards) {
		Collection<CCard> transformedCards = new ArrayList<CCard>( cards.size() );
		
		for (Card card : cards) {
			transformedCards.add( transformCard(card) );
		}
		
		return transformedCards;
	}
	
	private Collection<CProperty> transformPropertiesCollection( Collection<Property> properties) {
		Collection<CProperty> transformedProperties = new ArrayList<CProperty>( properties.size() );
		
		for (Property p : properties) {
			transformedProperties.add( transformProperty(p) );
		}
		
		return transformedProperties;
	}
	
	private CCardInstance transformCardInstance(CardInstance ci) throws TCGException {
		Set<Long> decks = ci.getDecks();
		
		long[] deckIds = new long[decks.size()];
		
		int i = 0;
		for (Long deckId : decks) {
			deckIds[i] = deckId.longValue();
				
			i++;
		}
		
		return new CCardInstance(ci.getId(), ci.getLatitude(), ci.getLongitude(),
				transformCard( dataManager.getCardById(ci.getCardId()) ), deckIds, ci.getCreated(), ci.getModified());
	}
	
	private CCard transformCard(Card c) {
		return new CCard(c.getId(), c.getName(), c.getLife(), c.getAttack(),
				c.getDefense(), c.getAgility(), c.getProperties(), c.getCreated(), c.getModified());
	}
	
	private CDeck transformDeck(Deck deck) {
		return new CDeck(deck.getId(), deck.getName(), deck.getUserId(),
				deck.getCardInstanceIdsAsArray(), deck.getCreated(), deck.getModified());
	}
	
	private CProperty transformProperty(Property p) {
		return new CProperty(p.getId(), p.getName(), p.getCreated(), p.getModified());
	}
	
	private CUser transformUser(User u) {
		return new CUser(u.getId(), u.isAdmin(),
				u.getUsername(), u.getPassword(), u.getCreated(), u.getModified());
	}
	
	private CNewGame transformNewGame(NewGame ng) {
		CardInstanceCollection[] decks = ng.getDecks();
		
		long[][] transformedDecks = new long[decks.length][decks[0].size()];
		
		int j;
		for (int i = 0; i < decks.length; i++) {
			j = 0;
			
			for (CardInstance ci : decks[i].getCollection()) {
				transformedDecks[i][j] = ci.getId();
				j++;
			}
		}
		
		Map<Long, CCard> inGameCards = new HashMap<Long, CCard>(ng.getInGameCards().size());
		for (Long cardId : ng.getInGameCards().keySet()) {
			inGameCards.put( cardId, transformCard( ng.getInGameCards().get(cardId) ) );
		}
		
		
		
		return new CNewGame(ng.getGameId(), ng.getPlayerIds(), transformedDecks, ng.getOtps(),
				inGameCards, ng.getPlayerToDeckMapping(), ng.getPlayerToOtpMapping());
	}

}
